import { MongodbClient } from "../lib/db.client.mongodb";
import { PgClient } from "../lib/db.client.pg";

import { Book, BookContactMap, BookMap, ENUM_BOOK_DIRECTION, TonOrder, TonOrderGroup, User } from "qqlx-core";
import { getConditionMatchStr, toDivideSafe, BookSchema, isAmountFromJie, BookMapSchema, BookContactMapSchema, getBookTypeTrans } from "qqlx-cdk";

import { User as OldUser } from "../../../qqlx.old/qqlx-core/dist";
import { Corp as OldCorp } from "../../../qqlx.old/qqlx-core/dist";
import { Order as OldOrder } from "../../../qqlx.old/qqlx-core/dist";

import { doBashPrint } from "../lib/log";
import { ObjectId } from "mongodb";
import { BookContactMapDao, BookDao, BookMapDao } from "../dao/pond";

export async function doBookSumInsert(mongo_master_corp_id: OldCorp["_id"], _id_to_user_map: Map<OldUser["_id"], User>) {
  const mongodbClient = new MongodbClient("mongodb://localhost:27017/qqlx");
  const pgClient = new PgClient("127.0.0.1", "5432", "production", "postgres", "postgres");

  const userOrderGroupMap = new Map<User["uuid32"], TonOrderGroup>();
  const oldToNewSaleOrderMap = new Map<OldOrder["_id"], TonOrder>();

  try {
    await mongodbClient.start();

    const colCorps = mongodbClient.getCollection("corps");
    const corp = (await colCorps.findOne<OldCorp>({ _id: mongo_master_corp_id as unknown as ObjectId })) as OldCorp;

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    const pgClientIns = await pgClient.start();
    const bookDao = new BookDao(pgClientIns.getRepository<Book>(BookSchema));
    const PgBookMapDao = new BookMapDao(pgClientIns.getRepository<BookMap>(BookMapSchema));
    const PgBookContactMapDao = new BookContactMapDao(pgClientIns.getRepository<BookContactMap>(BookContactMapSchema));

    const master = _id_to_user_map.get(corp.userId) as User;
    const condis = [getConditionMatchStr("refOwnerUUid32", master.uuid32)];
    const { list } = await bookDao.queryAll(condis);

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    // #region 按照交易ID进行统计
    const tradeIdAndTypeDirMap = new Map<string, [number, number]>();
    for (const book of list) {
      const key = `${book.tradeId}@${book.refCreatorId}@${book.refContactId}@${book.tradeYear}@${book.tradeMonth}@${book.tradeScope}@${book.type}`;
      const JieDai = tradeIdAndTypeDirMap.get(key) || [0, 0];

      if (book.direction === ENUM_BOOK_DIRECTION.JIE) JieDai[0] += book.amount;
      else if (book.direction === ENUM_BOOK_DIRECTION.DAI) JieDai[1] += book.amount;
      tradeIdAndTypeDirMap.set(key, JieDai);
    }

    const schemaTradeLs: BookMap[] = [];
    for (const [key, amount] of tradeIdAndTypeDirMap) {
      const [tradeId, creatorIdStr, contactIdStr, tradeYear, tradeMonth, tradeScope, type] = key.split("@");
      const Jie = toDivideSafe(amount[0], 100, 2);
      const Dai = toDivideSafe(amount[1], 100, 2);
      const amountFinal = (isAmountFromJie(Number(type)) ? 1 : -1) * (Jie - Dai);

      const schema: BookMap = new BookMapSchema();
      schema.tradeId = tradeId;
      schema.tradeTime = "0";
      schema.tradeYear = Number(tradeYear);
      schema.tradeMonth = Number(tradeMonth);
      schema.tradeScope = tradeScope;
      schema.refCreatorId = creatorIdStr;
      schema.refContactId = Number(contactIdStr); // 交易七要素

      schema.refOwnerUUid32 = master.uuid32;
      schema.type = Number(type);
      schema.remark = getBookTypeTrans(schema.type)?.zh || "";
      schema.amountJie = Jie.toString();
      schema.amountDai = Dai.toString();
      schema.amount = amountFinal.toString();
      schemaTradeLs.push(schema);
    }

    const batchCount = 2000;
    while (schemaTradeLs.length > 0) {
      const part = schemaTradeLs.splice(0, batchCount);
      await PgBookMapDao.insertManyAndQuery(part);
      doBashPrint(`正在为每笔交易进行记账（${batchCount}）剩余${schemaTradeLs.length}`);
    }
    // #endregion

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    // #region 按照联系人进行统计
    const contactIdAndTypeDirMap = new Map<string, [number, number]>();
    for (const book of list) {
      const key = `${book.refContactId}@${book.tradeYear}@${book.tradeMonth}@${book.tradeScope}@${book.type}`;
      const JieDai = contactIdAndTypeDirMap.get(key) || [0, 0];

      if (book.direction === ENUM_BOOK_DIRECTION.JIE) JieDai[0] += book.amount;
      else if (book.direction === ENUM_BOOK_DIRECTION.DAI) JieDai[1] += book.amount;
      contactIdAndTypeDirMap.set(key, JieDai);
    }

    const schemaContactLs: BookContactMap[] = [];
    for (const [key, amount] of contactIdAndTypeDirMap) {
      const [contactIdStr, tradeYear, tradeMonth, tradeScope, type] = key.split("@");
      const Jie = toDivideSafe(amount[0], 100, 2);
      const Dai = toDivideSafe(amount[1], 100, 2);
      const amountFinal = (isAmountFromJie(Number(type)) ? 1 : -1) * (Jie - Dai);

      const schema: BookContactMap = new BookContactMapSchema();
      schema.tradeId = "";
      schema.tradeTime = "0";
      schema.tradeYear = Number(tradeYear);
      schema.tradeMonth = Number(tradeMonth);
      schema.tradeScope = tradeScope;
      schema.refCreatorId = master.uuid32;
      schema.refContactId = Number(contactIdStr); // 交易七要素

      schema.refOwnerUUid32 = master.uuid32;
      schema.type = Number(type);
      schema.remark = getBookTypeTrans(schema.type)?.zh || "";
      schema.amountJie = Jie.toString();
      schema.amountDai = Dai.toString();
      schema.amount = amountFinal.toString();
      schemaContactLs.push(schema);
    }

    const batchCount2 = 2000;
    while (schemaContactLs.length > 0) {
      const part = schemaContactLs.splice(0, batchCount2);
      await PgBookContactMapDao.insertManyAndQuery(part);
      doBashPrint(`正在为每个联系人进行记账（${batchCount2}）剩余${schemaContactLs.length}`);
    }
    // #endregion

    // ==================== 结束 ====================
    // ==================== 结束 ====================
    // ==================== 结束 ====================
    // ==================== 结束 ====================
    // ==================== 结束 ====================
    // ==================== 结束 ====================

    console.log("====================================");
  } finally {
    await pgClient.stop();
    await mongodbClient.stop();
  }

  return { userOrderGroupMap, oldToNewSaleOrderMap };
}
